package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.CheckInApplyDto;
import com.zzyl.nursing.dto.CheckInElderDto;
import com.zzyl.nursing.mapper.*;
import com.zzyl.nursing.util.CodeGenerator;
import com.zzyl.nursing.util.IDCardUtils;
import com.zzyl.nursing.vo.CheckInConfigVo;
import com.zzyl.nursing.vo.CheckInDetailVo;
import com.zzyl.nursing.vo.CheckInElderVo;
import com.zzyl.nursing.vo.ElderFamilyVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.service.ICheckInService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 入住业务层处理
 */
@Service
public class CheckInServiceImpl extends ServiceImpl<CheckInMapper, CheckIn> implements ICheckInService {

    @Autowired
    private CheckInMapper checkInMapper;

    @Autowired
    private ElderMapper elderMapper;

    @Autowired
    private BedMapper bedMapper;

    @Autowired
    private ContractMapper contractMapper;

    @Autowired
    private CheckInConfigMapper checkInConfigMapper;

    //查询入住列表
    @Override
    public List<CheckIn> selectCheckInList(CheckIn checkIn) {
        return checkInMapper.selectCheckInList(checkIn);
    }

    //申请入住
    @Transactional(rollbackFor = Exception.class) //开启事务，当方法执行过程中抛出Exception类及其子类时，事务将会回滚
    @Override
    public void apply(CheckInApplyDto checkInApplyDto) {
        try {
            //判断老人是否已入住
            //创建LambdaQueryWrapper对象，用于构建查询条件
            LambdaQueryWrapper<Elder> elderQueryWrapper = new LambdaQueryWrapper<>();
            //根据身份证号查询
            elderQueryWrapper.eq(Elder::getIdCardNo, checkInApplyDto.getCheckInElderDto().getIdCardNo());
            //根据状态查询（0：禁用，1：启用，2：请假，3：退住中，4：入住中，5：已退住）
            elderQueryWrapper.eq(Elder::getStatus, 1);
            //执行查询，获取满足条件的老人对象
            Elder elder = elderMapper.selectOne(elderQueryWrapper);
            //判断查询结果是否非空，如果非空则抛出全局异常，提示老人已入住
            if (ObjectUtil.isNotEmpty(elder)) {
                throw new BaseException("老人已入住");
            }
            //根据床位ID查询床位信息
            Bed bed = bedMapper.selectById(checkInApplyDto.getCheckInConfigDto().getBedId());
            //更新床位状态为已入住（0：未入住，1：已入住，2：入住申请中）
            bed.setBedStatus(1);
            //更新床位信息
            bedMapper.updateById(bed);
            //新增或更新老人数据
            elder = insertOrUpdate(bed, checkInApplyDto.getCheckInElderDto());
            //生成合同编号
            String contractNo = "HT" + CodeGenerator.generateContractNumber();
            //新增签约办理
            insertContract(contractNo, elder, checkInApplyDto);
            //新增入住信息
            CheckIn checkIn = insertCheckIn(elder, checkInApplyDto);
            //新增入住配置信息
            insertCheckInConfig(checkIn.getId(), checkInApplyDto);
        } catch (BaseException e) {
            throw new BaseException("入住失败");
        }
    }

    //新增或更新老人数据
    private Elder insertOrUpdate(Bed bed, CheckInElderDto checkInElderDto) {
        //准备老人数据
        Elder elder = new Elder();
        //属性拷贝，将入住老人DTO复制到老人对象中
        BeanUtils.copyProperties(checkInElderDto, elder);
        //设置老人的床位编号和床位ID
        elder.setBedNumber(bed.getBedNumber());
        elder.setBedId(bed.getId());
        //设置老人状态为1（0：禁用，1：启用，2：请假，3：退住中，4：入住中，5：已退住）
        elder.setStatus(1);
        //创建LambdaQueryWrapper对象，用于构建查询条件
        LambdaQueryWrapper<Elder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //设置查询条件为身份证号匹配且状态为0（0：禁用，1：启用，2：请假，3：退住中，4：入住中，5：已退住）
        lambdaQueryWrapper.eq(Elder::getIdCardNo, checkInElderDto.getIdCardNo()).eq(Elder::getStatus, 0);
        //执行查询，获取符合条件的老人数据对象
        Elder elderDb = elderMapper.selectOne(lambdaQueryWrapper);
        //判断查询结果是否非空
        if (ObjectUtils.isNotEmpty(elderDb)) {
            //设置老人ID
            elder.setId(elderDb.getId());
            //更新老人数据
            elderMapper.updateById(elder);
        } else {
            //新增老人数据
            elderMapper.insert(elder);
        }
        return elder;
    }

    //新增签约办理
    private void insertContract(String contractNo, Elder elder, CheckInApplyDto checkInApplyDto) {
        //创建合同对象
        Contract contract = new Contract();
        //属性拷贝，将申请入住请求DTO中的签约办理信息复制到合同对象中
        BeanUtils.copyProperties(checkInApplyDto.getCheckInContractDto(), contract);
        contract.setElderId(elder.getId()); //设置老人ID
        contract.setElderName(elder.getName()); //设置老人姓名
        contract.setContractNumber(contractNo); //设置合同编号
        //获取开始时间和结束时间
        LocalDateTime checkInStartTime = checkInApplyDto.getCheckInConfigDto().getStartDate();
        LocalDateTime checkInEndTime = checkInApplyDto.getCheckInConfigDto().getEndDate();
        //根据当前时间判断合同的状态：如果当前时间在合同开始时间之后，则合同生效（0：未生效，1：已生效，2：已过期，3：已失效）
        Integer status = checkInStartTime.isAfter(LocalDateTime.now()) ? 1 : 0;
        //设置开始时间、结束时间、合同状态
        contract.setStartDate(checkInStartTime);
        contract.setEndDate(checkInEndTime);
        contract.setStatus(status);
        //新增合同数据
        contractMapper.insert(contract);
    }

    //新增入住信息
    public CheckIn insertCheckIn(Elder elder, CheckInApplyDto checkInApplyDto) {
        //创建入住对象
        CheckIn checkIn = new CheckIn();
        //设置老人姓名、老人ID、身份证号
        checkIn.setElderName(elder.getName());
        checkIn.setElderId(elder.getId());
        checkIn.setIdCardNo(elder.getIdCardNo());
        //设置入住开始时间和入住结束日期
        checkIn.setStartDate(checkInApplyDto.getCheckInConfigDto().getStartDate());
        checkIn.setEndDate(checkInApplyDto.getCheckInConfigDto().getEndDate());
        //设置护理级别名称
        checkIn.setNursingLevelName(checkInApplyDto.getCheckInConfigDto().getNursingLevelName());
        //设置入住床位号
        checkIn.setBedNumber(elder.getBedNumber());
        //设置入住状态（0：已入住，1：已退住）
        checkIn.setStatus(0);
        //设置备注信息，这里将老人家属信息序列化为JSON字符串
        checkIn.setRemark(JSONUtil.toJsonStr(checkInApplyDto.getElderFamilyDtoList()));
        //新增入住数据
        checkInMapper.insert(checkIn);
        return checkIn;
    }

    //新增入住配置信息
    private void insertCheckInConfig(Long checkInId, CheckInApplyDto checkInApplyDto) {
        //创建入住配置对象
        CheckInConfig checkInConfig = new CheckInConfig();
        //属性拷贝，将申请入住请求DTO中的入住配置信息复制到入住配置对象中
        BeanUtils.copyProperties(checkInApplyDto.getCheckInConfigDto(), checkInConfig);
        //设置入住ID
        checkInConfig.setCheckInId(checkInId);
        //新增入住配置数据
        checkInConfigMapper.insert(checkInConfig);
    }

    //查询申请入住详情
    @Override
    public CheckInDetailVo detail(Long id) {
        //创建入住详情视图对象
        CheckInDetailVo checkInDetailVo = new CheckInDetailVo();
        //通过ID找到入住记录，以便获取老人ID和其他相关信息
        CheckIn checkIn = checkInMapper.selectCheckInById(id);
        //根据入住记录中的老人ID查询老人信息
        Elder elder = elderMapper.selectById(checkIn.getElderId());
        //判断老人对象是否非空
        if (ObjectUtil.isNotEmpty(elder)) {
            //初始化老人入住信息视图对象
            CheckInElderVo checkInElderVo = new CheckInElderVo();
            //将老人对象属性复制到老人入住信息视图对象中
            BeanUtils.copyProperties(elder, checkInElderVo);
            //补全年龄属性，通过身份证号计算老人的年龄，工具类可以使用AI协助创建
            checkInElderVo.setAge(IDCardUtils.getAgeByIdCard(elder.getIdCardNo()));
            //将老人入住信息视图对象设置到入住详情视图对象中
            checkInDetailVo.setCheckInElderVo(checkInElderVo);
        }
        //创建查询包装器以查询入住配置
        LambdaQueryWrapper<CheckInConfig> checkInConfigWrapper = new LambdaQueryWrapper<>();
        //设置查询条件：入住ID等于给定的入住ID
        checkInConfigWrapper.eq(CheckInConfig::getCheckInId, checkIn.getId());
        //执行查询，获取唯一的入住配置对象
        CheckInConfig checkInConfig = checkInConfigMapper.selectOne(checkInConfigWrapper);
        //属性拷贝，将入住配置信息复制到CheckInConfigVo对象中，创建CheckInConfigVo对象
        CheckInConfigVo checkInConfigVo = BeanUtil.toBean(checkInConfig, CheckInConfigVo.class);
        //补全入住配置中的其他属性
        checkInConfigVo.setBedNumber(checkIn.getBedNumber()); //入住床位号
        checkInConfigVo.setStartDate(checkIn.getStartDate()); //入住开始时间
        checkInConfigVo.setEndDate(checkIn.getEndDate()); //入住结束时间
        //将入住配置视图对象设置到入住详情视图对象中
        checkInDetailVo.setCheckInConfigVo(checkInConfigVo);
        //创建查询包装器以查询与老人相关的合同信息
        LambdaQueryWrapper<Contract> contractWrapper = new LambdaQueryWrapper<>();
        //设置查询条件：老人ID等于给定的老人ID
        contractWrapper.eq(Contract::getElderId, elder.getId());
        //执行查询，获取合同信息
        Contract contract = contractMapper.selectOne(contractWrapper);
        //将合同信息设置到入住详情视图对象中
        checkInDetailVo.setContract(contract);
        //解析备注中的其他申请信息
        String otherApplyInfo = checkIn.getRemark();
        //将备注中的其他申请信息解析为家属列表视图对象
        List<ElderFamilyVo> elderFamilyVos = JSON.parseArray(otherApplyInfo, ElderFamilyVo.class);
        //将家属列表视图对象设置到入住详情视图对象中
        checkInDetailVo.setElderFamilyVoList(elderFamilyVos);
        //返回入住详情视图对象
        return checkInDetailVo;
    }
}